﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Text;


namespace EXEStart
{

    /// <summary>
    /// 为json序列化准备对象
    /// </summary>
    public class GameItem
    {
        /// <summary>
        /// TODO:添加icon路径和icon图标序号，属性界面增加图标选择功能
        /// </summary>
        [DataContract]
        public class ItemInfo
        {
            /// <summary>
            /// 排列顺序
            /// </summary>
            [DataMember]
            public int id;

            /// <summary>
            /// 显示名称
            /// </summary>
            [DataMember]
            public string name;

            /// <summary>
            /// 启动程序路径
            /// </summary>
            [DataMember]
            public string path;

            /// <summary>
            /// 显示图标
            /// </summary>
            [DataMember]
            public string image;

            /// <summary>
            /// 启动参数
            /// </summary>
            [DataMember]
            public string args;

            /// <summary>
            /// 启动窗口样式
            /// </summary>
            [DataMember]
            public int windowsSytle;

            /// <summary>
            /// 工作路经
            /// </summary>
            [DataMember]
            public string workingDir;

            /// <summary>
            /// 图标
            /// </summary>          
            public Image ImageICO;
        }

        /// <summary>
        /// 启动类型
        /// </summary>
        public enum RunType
        {
            Executable = 0,
            Directory = 1,
            Property = 2
        }

        private ItemInfo itemInfo;


        public GameItem(ItemInfo item)
        {
            this.itemInfo = item;
        }

        public GameItem(int id, string name, string path, Image img, string args = "", int winstyle = (int)ProcessWindowStyle.Normal, string dir = "")
        {
            itemInfo.id = id;
            itemInfo.name = name;
            itemInfo.path = path;
            itemInfo.image = imgToBase64(img);
            itemInfo.args = args;
            itemInfo.windowsSytle = winstyle;
            itemInfo.workingDir = dir;
            itemInfo.ImageICO = (Image)img.Clone();
        }

        /* public GameItem()
         {
             itemInfo.id =
             itemInfo.windowsSytle = 0;
             itemInfo.name =
             itemInfo.path =
             itemInfo.image =
             itemInfo.args =
             itemInfo.workingDir = String.Empty;
         }*/

        /// <summary>
        /// 保存ListView项目到json
        /// </summary>
        /// <param name="sFileName">json文件路径</param>
        /// <param name="items">项目列表</param>
        /// <returns>读取成功返回true，否则返回false</returns>
        public static string SaveItemsToJson(string sFileName, List<ItemInfo> items)
        {
            string message = String.Empty;
            try
            {
                using(StreamWriter sw = new(sFileName, false))
                {
                    var serializer = new DataContractJsonSerializer(typeof(List<ItemInfo>));
                    serializer.WriteObject(sw.BaseStream, items);
                }
            }
            catch(Exception e)
            {
                Console.WriteLine("\n\n\n写入文件错误：\n");
                Console.WriteLine(e.Message);

                message = e.Message;
            }
            return message;
        }

        /// <summary>
        /// 读取Json内容到ListView
        /// </summary>
        /// <param name="sFileName">json文件路径</param>
        /// <param name="items">包含列表项目的List</param>
        /// <returns>返回错误信息</returns>
        public static string ReadItemsFromJson(string sFileName, ref List<ItemInfo> items)
        {
            string message = String.Empty;
            if(!File.Exists(sFileName)) return message;
            try
            {
                using(StreamReader sr = new(sFileName))
                {
                    DataContractJsonSerializer deseralizer = new( typeof(List<ItemInfo>));
                    items = (List<ItemInfo>)deseralizer.ReadObject(sr.BaseStream);                   
                }
            }
            catch(Exception e)
            {
                Console.WriteLine("\n\n\n读取文件错误：\n");
                Console.WriteLine(e.Message);
                message = e.Message;
            }

            return message;
        }

        /// <summary>
        /// 对图像进行Base64编码
        /// </summary>
        /// <param name="img">要进行编码的图像</param>
        /// <returns>编码后的Base64字符串</returns>
        public static string imgToBase64(Image img)
        {
            if(img == null) return "";
            string base64String;
            byte[] bytes;

            using(MemoryStream ms = new())
            {
                img.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
                bytes = ms.ToArray();
            }
            base64String = Convert.ToBase64String(bytes);
            return base64String;
        }

        /// <summary>
        /// 转换Base64字符串为图像
        /// </summary>
        /// <param name="base64String">图像编码后的Base64字符串</param>
        /// <returns>成功返回图像，失败返回null</returns>
        public static Image Base64ToImg(string base64String)
        {
            Image img = null;
            if(string.IsNullOrEmpty(base64String)) return img;
            try
            {
                byte[] bytes = Convert.FromBase64String(base64String);
                using(MemoryStream ms = new(bytes, 0, bytes.Length))
                {
                    img = Image.FromStream(ms, false,true);
                }
            }
            catch { }
            return img;
        }

        public static async void RunEXE(Form parent, GameItem.ItemInfo itemInfo, GameItem.RunType type = GameItem.RunType.Executable, bool isHide = false)
        {
            //GameItem.ItemInfo itemInfo = getInfoFromItem(item);

            if(type == GameItem.RunType.Directory)
            {
                if(!File.Exists(itemInfo.path))
                {
                    MessageBox.Show($"'{itemInfo.name}' 打开错误！\n\n目标文件不存在！\n{itemInfo.path}", itemInfo.path, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                itemInfo.args = "/e,/select, " + itemInfo.path;
                itemInfo.path = "Explorer.exe";
            }

            try
            {
                if(type == GameItem.RunType.Property)
                {
                    Program.ShowFileProperties(itemInfo.path);
                    return;
                }

                if(isHide)
                {
                    parent.WindowState = FormWindowState.Minimized;
                }

                await Task.Run(() =>
                {
                    using(var proc = Process.Start(new ProcessStartInfo
                    {
                        WindowStyle = ExeArg.GetWindowStyle(itemInfo.windowsSytle),
                        FileName = itemInfo.path,
                        Arguments = itemInfo.args,
                        WorkingDirectory = itemInfo.workingDir
                        //UseShellExecute = false
                    }))
                    {
                        proc.WaitForExit();
                    };
                });

                if(isHide)
                {
                    parent.WindowState = FormWindowState.Normal;
                }

                Program.SetForegroundWindow(parent.Handle);
            }
            catch(Exception ex)
            {
                MessageBox.Show($"'{itemInfo.name}' 运行错误！\n\n{ex.Message}\n{itemInfo.path}", $"{itemInfo.path}", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
        }

    }



    /// <summary>
    /// 获取目标程序信息
    /// </summary>
    class ExeArg
    {
        public ExeArg() { }

        #region 属性
        /// <summary>
        /// 显示名字
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 图标路径
        /// </summary>
        public string IconLocation { get; set; }
        /// <summary>
        /// 备注
        /// </summary>
        public string Description { get; set; }
        public string TargetPath { get; set; }
        /// <summary>
        /// 程序参数
        /// </summary>
        public string Arguments { get; set; }
        /// <summary>
        /// 窗口样式：
        /// 常规窗口： 1，
        /// 最小化： 7，
        /// 最大化： 3
        /// </summary>
        public int WindowStyle { get; set; }
        /// <summary>
        /// 工作路径
        /// </summary>
        public string WorkingDirectory { get; set; }
        /// <summary>
        /// 热键
        /// </summary>
        public string Hotkey { get; set; }
        /// <summary>
        /// 快捷方式文件路径
        /// </summary>
        public string FullName { get; set; }
        /// <summary>
        /// 图标索引
        /// </summary>
        public int IcoIndex { get; set; }
        /// <summary>
        /// 目标文件扩展名
        /// </summary>
        //public string TargetExt => targetext;
        public string TargetExt { get; set; }

        //public string Load;
        //public string Save;

        #endregion

        public ExeArg(string filename)
        {
            string ext = Path.GetExtension(filename).ToLower();
            if(ext == ".lnk")
                GetExeArgFromLnk(filename);
            else
                GetExeArgFromExe(filename);
        }

        private void getExeIconIndex()
        {
            if(IconLocation.IndexOf(',') >= 0)// && iconLocation.Length > 0)
            {
                string[] s = IconLocation.Split(',');
                if(s[0].Length > 0)
                    IconLocation = s[0];
                else
                    IconLocation = TargetPath;
                try
                {
                    IcoIndex = int.Parse(s[1]);                   
                }
                catch(Exception)
                {
                    IcoIndex = 0;
                }
                return;

            }
            IconLocation = TargetPath;
        }

        public static ProcessWindowStyle GetWindowStyle(int style)
        {
            switch(style)
            {
                case 1:
                    return ProcessWindowStyle.Normal;
                case 7:
                    return ProcessWindowStyle.Minimized;
                case 3:
                    return ProcessWindowStyle.Maximized;
            }
            return ProcessWindowStyle.Normal;
        }

        /// <summary>
        /// 获取快捷方式信息
        /// </summary>
        /// <param name="filename"></param>
        private static readonly Guid CLSID_WshShell = new Guid("72C24DD5-D70A-438B-8A42-98424B88AFB8");

        private void GetExeArgFromLnk(string filename)
        {
            dynamic objWshShell = null, objShortcut = null;
            try
            {
                //Guid CLSID_WshShell = new("72C24DD5-D70A-438B-8A42-98424B88AFB8");

                objWshShell = Activator.CreateInstance(Type.GetTypeFromCLSID(CLSID_WshShell));
                objShortcut = objWshShell.CreateShortcut(filename);

                TargetPath = objShortcut.TargetPath;
                IconLocation = objShortcut.IconLocation;
                Description = objShortcut.Description;
                Arguments = objShortcut.Arguments;
                WindowStyle = (int)objShortcut.WindowStyle;
                WorkingDirectory = objShortcut.WorkingDirectory;
                Hotkey = objShortcut.Hotkey;
                FullName = objShortcut.FullName;
                Name = Path.GetFileNameWithoutExtension(filename);
                TargetExt = Path.GetExtension(TargetPath).ToLower();
                getExeIconIndex();

            }
            finally
            {
                System.Runtime.InteropServices.Marshal.ReleaseComObject(objShortcut);
                System.Runtime.InteropServices.Marshal.ReleaseComObject(objWshShell);
            }
        }

        private void GetExeArgFromExe(string filename)
        {
            TargetPath = filename;
            IconLocation = filename;
            Description = String.Empty;
            Arguments = String.Empty;
            WindowStyle = (int)ProcessWindowStyle.Normal;
            WorkingDirectory = Path.GetDirectoryName(filename);
            Hotkey = String.Empty;
            FullName = filename;
            Name = Path.GetFileNameWithoutExtension(filename);
            TargetExt = Path.GetExtension(filename).ToLower();
        }


        public bool isExe()
        {
            return TargetExt == ".exe" || TargetExt == ".cmd" || TargetExt == ".bat";
        }


    }

}
